#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <malloc.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libgen.h>

#include <glib.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

#include "tt-codefunc.h"
#include "http_fetcher.h"
#include "lmp-debug.h"
#include "lrcshow.h"
#include "lmp-lyric-download.h"

typedef struct _LyricId
{
	int no;
	char* id;
	char* artist;
	char* title;
} LyricId;

typedef struct {

GtkWidget *data1;
GtkWidget *data2;
GtkWidget *data;
} _DATA;


//static int user_select_no;
//static GSList* lyrics_list = NULL;

//static GtkWidget* selectordlg;

//void tt_lyrics_list_selection_dialog(GSList* list);
gchar* tt_http_request(char* url);
gchar* tt_encode_artist_title(const char* str);
void on_cancel_bt(GtkWidget *widget,GtkWidget *data);
void onListClick(GtkTreeView *tree_view, 
		GtkTreePath *path,
		GtkTreeViewColumn *column,
		gpointer userdata);
gboolean lrc_show_widget(GtkWidget *widget);
gboolean deal_with_tree(GtkTreeView *tree,GSList *list);
void on_search_bt(GtkWidget *widget,_DATA *data);
gboolean on_dialog_del(GtkWidget *widget,
                       GdkEvent  *event,
                       gpointer   user_data) ;
gboolean lrc_is_lrc_buf(gchar *buf);
gchar* tt_get_lyrics_list(const gchar* artist, const gchar* title);
gchar* tt_get_lyrics_content(gint id, gchar* artist, gchar* title);
GSList* tt_parse_lyricslist(gchar* xml);
void on_gtk_entry(GtkEntry *entry,GtkButton *data);

/*
void lyric_filename_set_to(gchar *name,LRC_FILE_FLAG flag)
{
#define lrc_max_paths 2
	static gchar lrc_name[512];
	static gchar *lrc_paths[lrc_max_paths] = {NULL};
	int i=0;

	switch (flag){
		case LRC_SET:
			strcpy(lrc_name,basename(name));
			while(i<lrc_max_paths&&lrc_paths[i]){
				g_free(lrc_paths[i]);
				lrc_paths[i++] = NULL;
			}
			lrc_paths[0] = g_strdup(name);
			lrc_paths[1] = g_strdup_printf("%s/Lyrics/%s",getenv("HOME"),lrc_name);
			lmp_debug("%s",name);
			break;
		case LRC_RD:
			while(lrc_paths[i]){
				if(access(lrc_paths[i],F_OK)==0){
					break;
				}else{
					fprintf(stderr,"%s:%s .\n",lrc_paths[i],strerror(errno));
				}
				i++;
			}
			break;
		case LRC_WD:
			while(lrc_paths[i]){
				gchar *tmpstr = dirname(g_strdup(lrc_paths[i]));
				if(access(tmpstr,W_OK)==0){
					g_free(tmpstr);
					break;
				}
//				lmp_debug("%s",tmpstr);
				if(access(tmpstr,F_OK)&&mkdir(tmpstr,S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)==-1)
						fprintf(stderr,"mkdir():%s\n",strerror(errno));
				g_free(tmpstr);
				i++;
			}
			break;
		default:
			i=0;
			break;
	}
//	lmp_debug("name=%s\\\nlrc_paths[i]=%s",name,lrc_paths[i]);
	if(lrc_paths[i])
			lyric_filename = lrc_paths[i];
	else
			lyric_filename = lrc_paths[0];
}
*/

gchar* tt_http_request(char* url)
{
	lmp_debug("");
	int ret;
	char *fileBuf = NULL;				/* Pointer to downloaded data */

	ret = http_fetch(url, &fileBuf);	/* Downloads page */
	lmp_debug("");
	if(ret == -1)						/* All HTTP Fetcher functions return */
	{
		http_perror("http_fetch");		/*	-1 on error. */
		return NULL;
	}
	
	lmp_debug("");
	return fileBuf;
}

//g_free when no use again.
gchar* tt_encode_artist_title(const char* str)
{
	lmp_debug("");
	int i, j;
	char temp[64];

	assert(str != NULL);
	int str_len = strlen(str);
	int utf16_len = g_utf8_strlen(str, str_len) * 2;

	lmp_debug("");
	char* re = g_new0(char, str_len * 6 + 1); //FIXME:这里应是多大才好呢？

	lmp_debug("");
	gunichar2* utf16_str = g_utf8_to_utf16(str, 
			str_len,
			NULL,
			NULL,
			NULL);

	lmp_debug("");
	char* p = (char*)utf16_str;

	lmp_debug("str: %s", str);
	for(i = 0, j = 0; i < utf16_len; ++i)
	{
		sprintf(temp, "%02x", p[i]);
		lmp_debug("i = %d, temp = %s", i, temp);
		int n = strlen(temp);
		re[j] = temp[n - 2];
		++j;
		re[j] = temp[n - 1];
		++j;
	}
	re[j] = '\0';

	lmp_debug("");
	g_free(utf16_str);
	return re;
}

//g_free when no use again.
static gchar* tt_remove_blankspace_lower(const gchar* src)
{
	lmp_debug("");

	gchar* s = NULL;
	int len = strlen(src);

	if(len == 0)
	{
		s = g_strdup("");
		return s;
	}

	lmp_debug("g_new0 begin: len(src) = %d", len);

	s = g_new0(gchar, len + 1);

	lmp_debug("g_new0 end");

	int i, j;
	for(i = 0, j = 0; i < len; ++i)
	{
		if(src[i] != ' ')
		{
			s[j] = g_ascii_tolower(src[i]);
			++j;
		}
	}
	s[j] = '\0';

	lmp_debug("");
	return s;
}

gchar* tt_get_lyrics_list(const gchar* artist, const gchar* title)
{
	lmp_debug("artist: %s, title: %s", artist, title);
//	assert(artist != NULL);
//	assert(title != NULL);
	if(!(artist||title))
		return NULL;
	gchar* art1 = tt_remove_blankspace_lower(artist);
	gchar* art2 = tt_encode_artist_title(art1);

	lmp_debug("g_free(art1)");
	g_free(art1); //FIXME:

	gchar* tit1 = tt_remove_blankspace_lower(title);
	gchar* tit2 = tt_encode_artist_title(tit1);
	g_free(tit1); //FIXME:

	gchar* url = g_strdup_printf( 
			"http://lrcct2.ttplayer.com/dll/lyricsvr.dll?sh?Artist=%s&Title=%s&Flags=0",
			art2, tit2);

	printf("url: %s\n", url);

	g_free(art2); //FIXME:
	g_free(tit2); //FIXME:
	gchar* xml = tt_http_request(url);
	lmp_debug("free url");
	g_free(url);

	return xml;
}

gchar* tt_get_lyrics_content(gint id, gchar* artist, gchar* title)
{
	lmp_debug("");
	gchar* art_tit = g_strconcat(artist, title, NULL);
	gchar* url = g_strdup_printf(
			"http://lrcct2.ttplayer.com/dll/lyricsvr.dll?dl?Id=%d&Code=%d&uid=01&mac=%012x",
			id, 
			tt_CodeFunc(id, art_tit), 
			g_random_int_range(0, 0x7FFFFFFF));

	lmp_debug("url = %s\n", url);

	gchar* head = tt_http_request(url);
	g_free(url);
	if(!head){
		return NULL;
	}
	gchar* buf =  g_strstrip(head);
	while(*buf){
		if(*buf=='[')
			break;
		buf++;
	}
	if(*buf){
		buf = g_strdup(buf);
	}else
		buf = NULL;
	g_free(head);
	lmp_debug("\n***\n%s\n*****", buf);

	return buf;
}

gboolean lrc_is_lrc_buf(gchar *buf)
{   ///用简单的方法来判断是否歌词的buffer。
	gint i=0;
	if(!buf)
		return FALSE;
	while(*buf){
		if(*buf==':'||*buf=='['||*buf==']'){
			i++;
			if(*buf==']')break;
		}
	buf++;
	}
	return (i>=3);
}

gboolean tt_get_lyrics_content_and_save(unsigned int id, 
		gchar* artist, 
		gchar* title)
{
	FILE* fp;
	gchar* buf = NULL;
	gint i = 0;
	while(!buf&&i<5){
		buf = tt_get_lyrics_content(id, artist, title);
		if(lrc_is_lrc_buf(buf))
			break;
		if(buf){
			g_free(buf);
			buf = NULL;
		}
		i++;
	}
	if(i>5&&!buf)
		return FALSE;
	lmp_debug("");
//	lyric_filename_set_to(NULL,LRC_WD);
	char *lyricfile = lrc_get_lrc_fullpath();
	lmp_debug(lyricfile);
	if(!lyricfile)
		goto ext;
	fp = fopen(lyricfile, "w+");
	i = 0;
	if(fp){
		i = fwrite(buf, strlen(buf), 1, fp);
		fclose(fp);
	}else{
		lmp_debug(strerror(errno));
	}
	ext:
	g_free(lyricfile);
	g_free(buf);
	return i>0;
}

GSList* tt_parse_lyricslist(gchar* xml)
{
	lmp_debug("");
	xmlDoc* doc;
	xmlNode* root_node;
	xmlNode* cur_node;

	GSList* list = NULL;
	int i = 0;

	if(xml == NULL)
		return NULL;

	doc = xmlReadDoc((const xmlChar *)xml, NULL, "UTF-8", 0);
	if(doc == NULL)
	{
		g_print("can't parse xml string\n");
		return NULL;
	}

	root_node = xmlDocGetRootElement(doc);
	if(root_node == NULL)
	{
		g_print("parse xml string failed\n");
		return NULL;
	}

	for(cur_node = root_node->children; cur_node; cur_node = cur_node->next)
	{
		LyricId* item = g_new0(LyricId, 1);
		item->no = i;
		item->id = (gchar*)xmlGetProp(cur_node,(const xmlChar *) "id");
		if(item->id == NULL) //FIXME: 为什么中间会有一个NULL元素
			continue;
		item->artist = (gchar*)xmlGetProp(cur_node,(const xmlChar *) "artist");
		item->title = (gchar*)xmlGetProp(cur_node, (const xmlChar *)"title");
		list = g_slist_append(list, item);
		++i;
	}

	xmlFreeDoc(doc);

	return list;
}


void onListClick(GtkTreeView *tree_view, 
		GtkTreePath *path,
		GtkTreeViewColumn *column,
		gpointer userdata)
{
	lmp_debug("");
	GtkTreeModel *model;
	GtkTreeIter iter;
	int index;
	char *label;
	static _THREAD_DATA da = {0};
	
	gtk_widget_set_sensitive(GTK_WIDGET(tree_view),FALSE);
	model = gtk_tree_view_get_model(tree_view);
	
	if(model && gtk_tree_model_get_iter(model, &iter, path))
	{
		gchar *art = NULL,*til = NULL;
		gtk_tree_model_get (GTK_TREE_MODEL(model), &iter,2,&index,1,&label,-1);
		art = label;
		while(*label){
		 if(*label=='-'){
		    *label=0;
		    til = ++label;
		  }else
		    label++;
		}
		da.id = index;
		da.artist = art;
		da.title = til;
		da.treeview = GTK_WIDGET(tree_view);
		GError *error = NULL;

		if(!g_thread_create((GThreadFunc)g_thread_on_down,&da,FALSE,&error)){
			gtk_widget_set_sensitive(GTK_WIDGET(tree_view),TRUE);
			g_free(art);
			fprintf(stderr,"Failed to create g_thread_on_search thread: %s\n", error->message);
			g_error_free(error);
		}
	}
	
}

gpointer g_thread_on_down(_THREAD_DATA *da)
{
	lmp_debug("");
	static GMutex *mutex = NULL;

	if(!mutex)
		mutex = g_mutex_new();
	g_mutex_lock(mutex);

	is_down_ok = FALSE;
	if(tt_get_lyrics_content_and_save(da->id,da->artist,da->title)){
		is_down_ok = TRUE;
		is_lrc_in_buff = FALSE;
		if(set_and_get_timeout(0)==0)
			kill(getpid(),sig_reload_lrc);
	}else {
		if(!is_down_ok){
			is_lrc_in_buff = FALSE;
			lrc_set_view("\n\n\n\n\n歌词下载失败！！");
		}
	}
//   lmp_debug("set to sensitive.");
	gdk_threads_enter();
	if(da->treeview&&GTK_IS_WIDGET(da->treeview)){
		lmp_debug("set to treeview sensitive.");
		gtk_widget_set_sensitive(da->treeview,TRUE);
	}
	if(da->data1&&GTK_IS_WIDGET(da->data1)){
		lmp_debug("set to button sensitive.");
		gtk_widget_set_sensitive(da->data1,TRUE);
	}
	gdk_flush();
	gdk_threads_leave();
	g_free(da->artist);
	g_mutex_unlock(mutex);
	lmp_debug("Thread exit .");
	return NULL;
}

static void on_down_bt(GtkWidget *widget,GtkTreeSelection *data)
{
	GtkTreeModel *model;
	GtkTreeIter iter;
	unsigned int index =0;
	gchar *label = NULL;
	static _THREAD_DATA da = {0};
	
	lmp_debug("");
	gtk_widget_set_sensitive(widget,FALSE);
	
	if(gtk_tree_selection_get_selected(data,&model,&iter))
	{
		gchar *art = NULL,*til = NULL;
		gtk_tree_model_get (GTK_TREE_MODEL(model), &iter,2,&index,1,&label,-1);
		art = label;
		lmp_debug("%s",label);
		while(*label){
			if(*label=='-'){
				*label=0;
				til = ++label;
			}else
				label++;
		}
		da.id = index;
		da.artist = art;
		da.title = til;
		da.data1 = widget;
		GError *error = NULL;

		if(!g_thread_create((GThreadFunc)g_thread_on_down,&da,FALSE,&error)){
			gtk_widget_set_sensitive(widget,TRUE);
			g_free(art);
			fprintf(stderr,"Failed to create g_thread_on_down thread: %s\n", error->message);
			g_error_free(error);
		}
	}else{
		gtk_widget_set_sensitive(widget,TRUE);
		lmp_debug("fucking wrong.");
	}
// gtk_button_leave(widget);
}


void on_cancel_bt(GtkWidget *widget,GtkWidget *data)
{
	gtk_widget_hide(data);
}

/*
gboolean lrc_show_widget(GtkWidget *widget)
{
 lmp_debug("");
 gtk_widget_show_all(widget);
 return FALSE;
}
*/

gpointer g_thread_on_search(_THREAD_DATA *da)
{
	lmp_debug("");
	static GMutex *mutex = NULL;

	if(!mutex)
		mutex = g_mutex_new();

	gchar *artist = da->artist;
	gchar *title = da->title;
	int id = da->id;

	g_mutex_lock(mutex);
	lmp_debug("artist:%s title: %s.",da->artist,da->title);

	gchar* xml = tt_get_lyrics_list(artist,title);
	if(!id){
		lmp_debug("free artist.");
		g_free(artist);
		lmp_debug("free title.");
		g_free(title);
	}
	GSList *lyrics_list = tt_parse_lyricslist(xml);
	if(xml)
		g_free(xml);
	if(lyrics_list){
		guint num = g_slist_length(lyrics_list);
		if(num == 1&&!id){
			LyricId* item = g_slist_nth_data(lyrics_list, 0);
			unsigned int id = atoi(item->id);
			if(tt_get_lyrics_content_and_save(id, item->artist, item->title)){
				is_down_ok = TRUE;
				is_lrc_in_buff = FALSE;
				if(set_and_get_timeout(0)==0)
					kill(getpid(),sig_reload_lrc);
			}else{
				if(!is_down_ok){
					is_lrc_in_buff = FALSE;
					gdk_threads_enter();
					lrc_set_view("\n\n\n\n\n歌词下载失败！！");
					gdk_threads_leave();
				}
			}
		}else{
			gdk_threads_enter();
			if(deal_with_tree(GTK_TREE_VIEW(da->treeview),lyrics_list)){
//				gdk_threads_enter();
				lrc_set_view("\n\n\n\n\nLyric find !");
//				gdk_threads_leave();
				lmp_debug("deal_with_tree ok");
			}
			gtk_widget_show_all(lrc_selection_dialog(NULL));
			lmp_debug("gdk_flush");
			gdk_flush();
			gdk_threads_leave();
		}
		g_slist_foreach(lyrics_list,(GFunc)g_free,NULL);
		g_slist_free(lyrics_list);
	}else{
		if(!is_down_ok){
			is_lrc_in_buff = FALSE;
			gdk_threads_enter();
			lrc_set_view("\n\n\n\n\n    抱歉，搜索失败！！     ");
			gdk_threads_leave();
		}
	}

	if(GTK_IS_WIDGET(da->data1)){
		gdk_threads_enter();
		gtk_widget_set_sensitive(da->data1,TRUE);
		gdk_threads_leave();
	}
	g_mutex_unlock (mutex);
	lmp_debug("Thread exit .");
	return NULL;
}

void on_gtk_entry(GtkEntry *entry,GtkButton *data)
{
	if(GTK_WIDGET_IS_SENSITIVE(data))
		gtk_button_clicked(data);
	lmp_debug("do entry");
}

void on_search_bt(GtkWidget *widget,_DATA *data)
{
	lmp_debug("");
	gchar *art,*til;
	static _THREAD_DATA da = {0};
	GError *error = NULL;

	art = (gchar*)gtk_entry_get_text(GTK_ENTRY(data->data1));
	til = (gchar*)gtk_entry_get_text(GTK_ENTRY(data->data2));

	if(!(*art||*til))return;

	gtk_list_store_clear(
				GTK_LIST_STORE(
				gtk_tree_view_get_model(
				GTK_TREE_VIEW(data->data))));

	gtk_widget_set_sensitive(widget,FALSE); 

	da.treeview = data->data;
	da.artist = art;
	da.title = til;
	da.data1 = widget;
	da.id = 1;

	if(!g_thread_create((GThreadFunc)g_thread_on_search,&da,FALSE,&error)){
		gtk_widget_set_sensitive (da.data1,TRUE);
		if(gtk_widget_is_focus(da.data1)){
			lmp_debug("is focus.");
			gtk_widget_grab_focus(da.data1);
		}
		lrc_set_view("\n\n\n\n\n创建搜索线程失败，搜索失败！！");
		fprintf(stderr,"Failed to create g_three_on_search thread: %s\n", error->message);
		g_error_free(error);
	}
}

gpointer *get_store_pointer(gpointer data)
{
	static gpointer da;
	if(data) da = data;
	return da;
}

gboolean deal_with_tree(GtkTreeView *tree,GSList *list)
{
	GtkTreeModel *model;
	GtkTreeIter iter;
	gint i=0;
	model = gtk_tree_view_get_model(tree);
	if(!model)
		model = GTK_TREE_MODEL(
		                      gtk_list_store_new (3,G_TYPE_INT, G_TYPE_STRING,G_TYPE_INT)
		);
	gtk_list_store_clear(GTK_LIST_STORE(model));
	GSList *l = list;
	for(l = list; l; l = l->next)
	{
		LyricId* id = (LyricId*)l->data;
		gchar* label = g_strdup_printf("%s---%s", 
				g_strchomp(id->artist),
				g_strchomp(id->title));
		gtk_list_store_append (GTK_LIST_STORE (model), &iter);
		gtk_list_store_set(GTK_LIST_STORE (model), 
								&iter,
								0,
								i,
								-1);
		gtk_list_store_set (GTK_LIST_STORE (model), 
									&iter,
									1,
									label,
									-1);
		gtk_list_store_set (GTK_LIST_STORE (model), 
									&iter,
									2,
									atoi(id->id),
									-1);
		lmp_debug("%s", label);
		i++;
	}///function who call deal_with_tree will free list

	lmp_debug("return");
	return !(!i);
}

gboolean on_dialog_del(GtkWidget *widget,
                       GdkEvent  *event,
                       gpointer   user_data) 
{
	gtk_widget_hide(widget);
	return TRUE;
}

GtkWidget *lrc_selection_dialog(gchar *ui)
{
	static GladeXML *xml = NULL;
	static GtkWidget *dialog = NULL;
	static _DATA data={NULL};
	GtkWidget *tree;
	GtkWidget *cancel;
	GtkWidget *down;
	GtkWidget *search;
	GtkTreeViewColumn* col;
	GtkCellRenderer* renderer;
	GtkListStore *model;

	if((!GTK_IS_WIDGET(dialog)||!xml)&&ui){
		if(access(ui,F_OK)==0)
			xml = glade_xml_new(ui,NULL, NULL);
		else{
			fprintf(stderr,"%s():%s.\n",__FUNCTION__,strerror(errno));
			return NULL;
		}

		model = gtk_list_store_new (3,G_TYPE_INT, G_TYPE_STRING,G_TYPE_INT);
		tree = glade_xml_get_widget(xml,"treeview1");
		dialog = glade_xml_get_widget(xml,"dialog1");
		cancel = glade_xml_get_widget(xml,"button1");
		down = glade_xml_get_widget(xml,"button2");
		search = glade_xml_get_widget(xml,"button3");

		data.data = tree;
		lrc_text.artist = data.data1 = glade_xml_get_widget(xml,"entry1");
		lrc_text.title = data.data2 = glade_xml_get_widget(xml,"entry2");
		get_store_pointer(tree);

		gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (model));

		renderer = gtk_cell_renderer_text_new();
		col = gtk_tree_view_column_new_with_attributes ("序号",
		                                                renderer,
		                                               "text", 0,
		                                                NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);

		col = gtk_tree_view_column_new_with_attributes ("歌名",
		                                                renderer,
		                                               "text", 1,
		                                                NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);

		col = gtk_tree_view_column_new_with_attributes ("ID",
		                                                renderer,
		                                                "text", 2,
		                                                 NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW (tree), col);

		GtkTreeSelection *select;
		select = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree));
		gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
//	g_signal_connect(G_OBJECT(select), "changed",
//			G_CALLBACK(tree_selection_changed), NULL);

		g_signal_connect(G_OBJECT(dialog),
			"delete-event",
			G_CALLBACK(on_dialog_del),NULL);

		g_signal_connect(G_OBJECT(dialog),
			"destroy-event",
			G_CALLBACK(on_dialog_del),NULL);

		g_signal_connect(down,
			"clicked",
			G_CALLBACK(on_down_bt),select);
			
		g_signal_connect(down,
			"activate",
			G_CALLBACK(on_down_bt),select);
			
		g_signal_connect(cancel,
			"clicked",
			G_CALLBACK(on_cancel_bt),dialog);
			
		g_signal_connect(GTK_ENTRY(data.data1),
			"activate",
			G_CALLBACK(on_gtk_entry),search);

		g_signal_connect(GTK_ENTRY(data.data2),
			"activate",
			G_CALLBACK(on_gtk_entry),search);

		g_signal_connect(search,
			"clicked",
			G_CALLBACK(on_search_bt),&data);
			
		g_signal_connect(G_OBJECT(tree), 
			"row-activated", 
			G_CALLBACK(onListClick), NULL);
			
		}

 return dialog;
}




